package com.cskaoyan.javase.oop3._3inner._5lambda._1basic;

/**
 * lambda表达式的进一步简化
 * Lambda表达式能够简化的前提是：它是功能接口的子类对象，而功能接口中有且只有一个必须要实现的抽象方法！
 * 因为只有一个抽象方法需要实现,所以做简化不会产生歧义.
 * 语法:
 * (形参列表) -> {
 *  // 方法体
 * }
 *
 * 1.形参列表能不能简化?
 * 可以简化,首先数据类型可以简化,因为重写的方法已经确定了,即便不写数据类型,形参的类型也是那些.
 * 特殊情况下,如果形参的变量只有一个,小括号可以去掉
 * 当然,如果方法是无参的,小括号是不能省略的
 *
 * 2.大括号能不能去掉呢?
 * 可以的,如果lambda表达式重写方法的方法体只有一个,那么可以去掉大括号
 * 特殊的,当方法有返回值语句,且有一条返回值语句时,可以把return和大括号一起省略
 *
 * 3.实际上在多数情况下，都不太可能一句话把方法体写完。多数情况下，Lambda表达式的抽象方法实现都会很复杂，那这样Lambda表达式就会写的很复杂，这就很难受了.
 * 这时为了简化Lambda表达式,lambda表达式中方法的实现可以不自己写,而是指向一个已经存在的方法,这种方式称之为"方法引用"
 *
 * lambda表达式指向一个已存在方法实现的语法:
 *      (形参列表) -> 已实现的方法(形参列表);
 *
 * 这个方法引用的语法还是可以更简洁的：
 *     父接口的名字 引用名 = 方法的归属者::方法名;
 *  方法的归属者怎么判断?
 *      成员方法: 属于对象,填入对象名
 *      静态成员方法: 属于类,填入类名
 *
 *
 * 注意事项:
 *      1.和局部内部类一样,访问局部变量,是一个常量
 *      2.和局部内部类,匿名内部类不同的是,lambda表达式没有自身的作用域,它和方法/局部位置共用一个作用域
 *
 * @since 16:17
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        int num = 10;
        INoReturnTwoParam ip1 = (a, b) -> {
            // Variable 'num' is already defined in the scope
            // int num = 100;
            System.out.println(num);
            // num = 100;
            System.out.println(a + b);
        };
        ip1.test(1, 1);

        INoReturnOneParam ip2 = a -> System.out.println(a);
        ip2.test(999);

        IHasReturnOneParam ip3 = a -> a;

        System.out.println(ip3.method(77777));

        IHasReturnTwoParam ip4 = (a, b) -> testInterface(a, b);
        System.out.println(ip4.test(10, 10));

        System.out.println("-------------------------");

        Student[] studs = new Student[3];
        studs[0] = new Student(18, "张三");
        studs[1] = new Student(28, "李四");
        studs[2] = new Student(88, "麻子");
        myMethod(studs);

        System.out.println("-------------------------");
        TraverseArray ta = Demo::myMethod;
        ta.traverseObjArr(studs);
    }

    public static int testInterface(int a, int b) {
        for (int i = 0; i < 5; i++) {
            System.out.println("我喜欢你啊!");
        }
        return a + b;
    }

    public static void myMethod(Object[] arr) {
        for (Object o : arr) {
            // 需要强转引用
            if (o instanceof Student) {
                Student stu = (Student) o;
                stu.print();
            }
        }
    }
}

@FunctionalInterface
interface TraverseArray {
    // 遍历对象数组
    void traverseObjArr(Object[] arr);
}

class Student {
    int age;
    String name;

    public Student() {
    }

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public void print() {
        System.out.println("名字为：" + name + "的学生,ta的年纪是:" + age);
    }
}

//无返回值无参数的功能接口
@FunctionalInterface
interface INoReturnNoParam {
    void test();
}

//无返回值有一个参数的功能接口
@FunctionalInterface
interface INoReturnOneParam {
    void test(int a);
}

//无返回值两个参数的功能接口
@FunctionalInterface
interface INoReturnTwoParam {
    void test(int a, int b);
}

//有返回值无参数的功能接口
@FunctionalInterface
interface IHasReturnNoParam {
    int test();
}

//有返回值一个参数的功能接口
@FunctionalInterface
interface IHasReturnOneParam {
    int method(int a);
}

//有返回值两个参数的功能接口
@FunctionalInterface
interface IHasReturnTwoParam {
    int test(int a, int b);
}